﻿/*
 * Twipler - Twitter Web Client with features.
 *  
 *  Copyright (C) 2009, 2010. Ian Quigley
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details. 
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 */

using System;
using System.Collections.Generic;

using Twipler.Data.Entity.Twipler;

using NHibernate.Criterion;
using System.Runtime.Serialization;
using Twipler.Data.Access;

namespace Twipler.Data.Entity.Theme
{
    public enum DesignState
    {
        Deleted = 0,
        Published = 1,
        Private = 2
    }

    public class Design : Base, ICloneable
    {
        public Design() : base()
        {
            State = DesignState.Private;
            CreatedBy = App.Current.Visitor;           
        }

        [EditOrder(1)]
        [EditStringType(EditStringType.Types.Required)]
        public virtual string Name { get; set; }
                
        [EditOrder(2)]
        [EditCondition(EditCondition.Condition.IsThemeModerator)]
        public virtual DesignState State { get; set; }

        [EditOrder(3)]
        [EditSelectFrom("Containers")]
        public virtual Container FirstPage { get; set; }

        [EditOrder(4)]
        [EditReadonly]
        public virtual Visitor CreatedBy { get; set; }

        [EditOrder(5)]
        [EditIf("UserCanModify_AllowCopy")]
        public virtual bool AllowCopy { get; set; }

        [EditOrder(6)]
        [EditReadonly]
        public virtual Design CopiedDesign { get; set; }

        [EditOrder(7)]
        public virtual bool AllowStyle { get; set; }

        [EditOrder(8)]
        [EditSelectFrom("Styles")]
        public virtual Style DefaultStyle { get; set; }

        [EditIgnore]
        public virtual int UseCount
        {
            get
            {
                return (int)Factory.Visitor.Criteria(Restrictions.Eq("Design", this))
                                .SetProjection(Projections.Count("Id"))
                                .UniqueResult();
            }
        }
        

        public override bool UserCanCreate()
        {
            return App.Current.Visitor.HasRole(VisitorRole.ThemeCreator);
        }

        public override bool UserCanModify()
        {
            return App.Current.Visitor.HasRole(VisitorRole.ThemeModerator) ||
                  (CreatedBy != null && CreatedBy.Id == App.Current.Visitor.Id);
        }

        public virtual bool UserCanModify_AllowCopy()
        {
            return (this.CopiedDesign == null);
        }

        public virtual List<Container> Containers()
        {
            if (this.Id == 0)
                return null;

            return Data.Access.Factory.Container.GetByCriteria(Restrictions.Eq("ParentDesign", this));
        }

        public virtual List<Block> Blocks()
        {
            if (this.Id == 0)
                return null;

            return Data.Access.Factory.Block.GetByCriteria(Restrictions.Eq("ParentDesign", this));
        }

        public virtual List<Style> Styles()
        {
            if (this.Id == 0)
                return null;

            return Data.Access.Factory.Style.GetByCriteria(Restrictions.Eq("ParentDesign", this));
        }

        public virtual List<Container> FindContainer(string containerName)
        {
            return Data.Access.Factory.Container.GetByCriteria(
                Restrictions.And(
                    Restrictions.Eq("ParentDesign", this),
                    Restrictions.Eq("Name", containerName)));                
        }

        public virtual List<Block> FindBlock(string containerName)
        {
            return Data.Access.Factory.Block.GetByCriteria(
                Restrictions.And(
                    Restrictions.Eq("ParentDesign", this),
                    Restrictions.Eq("Name", containerName)));
        }

        public virtual List<Design> PublishedAllowCopy()
        {
            return Data.Access.Factory.Design.GetByCriteria(
                Restrictions.And(
                    Restrictions.Eq("AllowCopy", true),
                    Restrictions.Eq("State", (int)DesignState.Published)));
        }

        public override string ToString()
        {
            return Name;
        }

        
        public virtual object Clone()
        {
            Design design = new Design()
            {
                Name = "Copy of " + this.Name,
                AllowCopy = this.AllowCopy,
                AllowStyle = this.AllowStyle,
                CopiedDesign = this,
                CreatedBy = App.Current.Visitor,
                DefaultStyle = null,
                FirstPage = null,
                Id = 0,
                State = DesignState.Private               
            };

            Factory.SaveOrUpdate(design);

            foreach (Container container in Containers())
                container.Clone(design);

            foreach (Block block in Blocks())
                block.Clone(design);
           
            return design;
        }

        public virtual void Delete()
        {
            if (!UserCanModify())
                return;

            FirstPage = null;
            DefaultStyle = null;
            Factory.Design.SaveOrUpdate(this);

            Blocks().ForEach(block => Factory.Block.Delete(block));
            Containers().ForEach(container => Factory.Container.Delete(container));
            Styles().ForEach(style => Factory.Style.Delete(style));

            Factory.Design.Delete(this);
        }
    }
}
